//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<XGfxShow.cpp>
///	@path	~/src/appear/xgfx/
///	@date	2008/10/14
///	@brief	.

#include "config/config.h"

#include "object/CVar.h"

#include "graphics/IRenderer.h"
#include "graphics/ITexture.h"

#include "appear/xgfx/XGfxShow.h"

namespace xeres {

	IMPL_IOBJECT_CLASS_DYNAMIC( XGfxShow );

	// XGfxShow
	XGfxShow::XGfxShow( void )
		: m_paramElapse( 0.1 )
		, m_paramMagnify( 20 )
		, m_paramFadeType( FADE_OUT )
		, m_tickElapsed( 0 )
	{
	}

	// XGfxShow
	XGfxShow::~XGfxShow( void )
	{
		m_alpha = NULL;
		m_texture = NULL;
		m_technique = NULL;
		m_effect = NULL;
	}

	// SetComp
	void XGfxShow::SetComp( RefWeak<IGuiComp> comp )
	{
		m_comp = comp;
		m_tickElapsed = 0;
	}

	// GetComp
	RefWeak<IGuiComp> XGfxShow::GetComp( void )
	{
		return m_comp;
	}

	// SetParam
	bool XGfxShow::SetParam( const WString& name , Ref<IVar> val )
	{
		if( name == _S("elapse") )
		{
			return val->GetFloat( m_paramElapse );
		}
		else if( name == _S("magnify") )
		{
			return val->GetFloat( m_paramMagnify );
		}
		else if( name == _S("type") )
		{
			return val->GetInt( m_paramFadeType );
		}
		return false;
	}

	// GetParam
	RefPass<IVar> XGfxShow::GetParam( const WString& name )
	{
		if( name == _S("elapse") )
		{
			return new CVar( m_paramElapse );
		}
		else if( name == _S("magnify") )
		{
			return new CVar( m_paramMagnify );
		}
		else if( name == _S("type") )
		{
			return new CVar( (int)m_paramFadeType );
		}
		else if( name == _S("tick") )
		{
			return new CVar( m_tickElapsed / m_paramElapse );
		}
		return NULL;
	}

	// GetParamList
	StringSeq XGfxShow::GetParamList( void )
	{
		static StringSeq s_paramSeq;
		if( s_paramSeq.empty() )
		{
			s_paramSeq.push_back( _S("float:tick") );
			s_paramSeq.push_back( _S("float:elapse") );
			s_paramSeq.push_back( _S("float:magnify") );
			s_paramSeq.push_back( _S("int:type") );
		}
		return s_paramSeq;
	}

	// Reset
	void XGfxShow::Reset( void )
	{
		m_tickElapsed = 0;
	}

	// Tick
	bool XGfxShow::Tick( float dTime )
	{
		if( m_tickElapsed >= m_paramElapse )
		{
			m_tickElapsed = 0;
			return false;
		}
		m_tickElapsed += dTime;

		// make alpha
		if( m_tickElapsed > m_paramElapse )
			m_tickElapsed = m_paramElapse;
		return true;
	}

	namespace
	{
		struct _GfxVertex
		{
			FLOAT x, y, z, rhw;
			float u , v;
		};

static const char * shader = "\n\
texture FrameTexture;\n\
sampler FrameSampler = sampler_state {\n\
    Texture = <FrameTexture>;\n\
    MinFilter = LINEAR;\n\
    MagFilter = LINEAR;\n\
};\n\
float AlphaValue;\n\
float4 EffectProcess( float2 t : TEXCOORD0 ) : COLOR0 {\n\
	return tex2D( FrameSampler , t ) * float4( 1 , 1 , 1 , AlphaValue );\n\
}\n\
technique RenderFrame {\n\
    pass P0 {\n\
		AlphaBlendEnable = TRUE;\n\
		SeparateAlphaBlendEnable = TRUE;\n\
        VertexShader = NULL;\n\
        PixelShader  = compile ps_2_0 EffectProcess();\n\
    }\n\
}\n\
";
	}

	// Render
	void XGfxShow::Render( RenderContext& rc , RefWeak<ITexture> texture )
	{
		if( m_effect.IsNull() )
		{
			m_effect = rc.GetRenderer()->CreateEffect( shader , strlen(shader) , NULL );
			m_technique = m_effect->GetTechnique( "RenderFrame" );
			m_texture = m_effect->GetVariableByName( "FrameTexture" );
			m_alpha = m_effect->GetVariableByName( "AlphaValue" );
		}

		Pair<int> start = m_comp->GetScreenPosition();
		Pair<int> size = m_comp->GetSize();

		float alpha = m_tickElapsed / m_paramElapse;
		float zoom = alpha;
		if( m_paramFadeType == FADE_OUT )
		{
			alpha = ( 1- alpha );
		}
		else
		{
			zoom = ( 1 - alpha );
		}
		zoom *= m_paramMagnify;

		m_texture->SetByTexture( texture );
		m_alpha->SetByData( &alpha , sizeof(float) );
		{
			Rect<float> placement( start , Pair<float>(start + size) );

			float ratio = placement.width() / placement.height();
			placement.extend( Pair<float>( zoom , zoom / ratio ) );
			if( placement.is_empty() )
			{
				Pair<float> center( start + size );
				center /= 2;
				Rect<float> placement( center , center + 1 );
			}

			float px = float(placement.left()) , py = float(placement.top()) ,
				sx = float(placement.right()) , sy = float(placement.bottom());
			float iw = 1 / float(placement.width());
			float ih = 1 / float(placement.height());
			_GfxVertex frame_vert[] = {
				{ px , py , 0.9f , 1.f , iw  , ih, },
				{ sx , py , 0.9f , 1.f , 1.f , ih, },
				{ px , sy , 0.9f , 1.f , iw  , 1.f, },
				{ sx , sy , 0.9f , 1.f , 1.f , 1.f, },
			};

			UINT pass = 0;
			do 
			{
				m_technique->Begin( pass , rc );
				rc.GetDX9()->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP , 2 , &frame_vert , sizeof(_GfxVertex) );
				m_technique->End( pass , rc );
			}while(pass);
		}
		m_texture->SetByTexture( NULL );
	}

} // namespace xeres
